/*
 * Copyright (c) 2014, Mentor Graphics Corporation
 * Copyright (c) 2015 Xilinx, Inc.
 * Copyright (c) 2016 Freescale Semiconductor, Inc.
 * Copyright 2016-2022 NXP
 * Copyright 2021 ACRIOS Systems s.r.o.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef RPMSG_ENV_H_
#define RPMSG_ENV_H_

#include <stdint.h>
#include "rpmsg_default_config.h"
#include "rpmsg_env_specific.h"
#include "rpmsg_platform.h"

/**
 * @brief  初始化OS/BM环境.
 * @param  env_context 指向预分配环境上下文数据的指针.
 * @param  env_init_data 指向环境层的初始化数据的指针.
 * @return 返回执行状态.
 */
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
int32_t env_init(void **env_context, void *env_init_data);
#else
int32_t env_init(void);
#endif

/**
 * @brief  反初始化OS/BM环境.
 * @param  env_context 指向环境上下文数据的指针.
 * @return 返回执行状态.
 */
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
int32_t env_deinit(void *env_context);
#else
int32_t env_deinit(void);
#endif

/**
 * @brief  分配指定大小的内存.
 * @param  size 要分配的内存大小.
 * @return 返回指向分配的内存的指针.
 */
void *env_allocate_memory(uint32_t size);

/**
 * @brief  释放分配内存.
 * @param  ptr 指向要释放内存的指针.
 */
void env_free_memory(void *ptr);

void env_memset(void *ptr, int32_t value, uint32_t size);
void env_memcpy(void *dst, void const *src, uint32_t len);
int32_t env_strcmp(const char *dst, const char *src);
void env_strncpy(char *dest, const char *src, uint32_t len);
int32_t env_strncmp(char *dest, const char *src, uint32_t len);
#ifdef MCUXPRESSO_SDK
/* MCUXpresso_SDK's PRINTF used in SDK examples */
#include "fsl_debug_console.h"
#if defined SDK_DEBUGCONSOLE && (SDK_DEBUGCONSOLE != DEBUGCONSOLE_DISABLE)
#define env_print(...) (void)PRINTF(__VA_ARGS__)
#else
#define env_print(...)
#endif
#else
/* 当RPMsg_Lite在MCUXpresso_SDK外部使用时, 使用您自己的env_print */
#include <stdio.h>
#define env_print(...) (void)printf(__VA_ARGS__)
#endif /* MCUXPRESSO_SDK */

/**
 * @brief  将逻辑地址转换为物理地址.
 * @param  env 指向环境上下文数据的指针.
 * @param  address 指向逻辑地址的指针.
 * @return 返回物理地址.
 */
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
uint32_t env_map_vatopa(void *env, void *address);
#else
uint32_t env_map_vatopa(void *address);
#endif

/**
 * @brief  将物理地址转换为逻辑地址.
 * @param  env_context 指向环境上下文数据的指针.
 * @param  address 指向物理地址的指针.
 * @return 返回裸机地址.
 *
 */
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
void *env_map_patova(void *env, uint32_t address);
#else
void *env_map_patova(uint32_t address);
#endif

/** @brief 插入内存屏障. */
void env_mb(void);

/** @brief 插入读内存屏障. */
void env_rmb(void);

/** @brief 插入写内存屏障. */
void env_wmb(void);

/**
 * @brief  创建一个具有给定初始计数的互斥锁.
 * @param  lock 指向创建的互斥锁的指针.
 * @param  count 初始计数0或1.
 * @param  context 指向互斥锁上下文的指针.
 * @return 返回函数执行状态.
 */
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
int32_t env_create_mutex(void **lock, int32_t count, void *context);
#else
int32_t env_create_mutex(void **lock, int32_t count);
#endif

/**
 * @brief  删除互斥锁.
 * @param  lock 指向要删除的互斥锁的指针.
 */
void env_delete_mutex(void *lock);

/**
 * @brief  尝试获取互斥锁, 即上锁, 如果锁不可用, 则对该函数的调用将挂起.
 * @param  lock 指向要获取的互斥锁的指针.
 *
 */
void env_lock_mutex(void *lock);

/**
 * @brief  释放互斥锁, 即解锁.
 * @param  lock 指向要舒服的互斥锁的指针.
 */
void env_unlock_mutex(void *lock);

/**
 * @brief  创建同步锁. 当信号必须从中断上下文发送到主线程上下文时使用.
 * @param  lock 指向创建的同步锁的指针.
 * @param  state 初始状态, 上锁或解锁.
 * @param  context 指向同步锁的上下文的指针.
 * @return 返回函数执行状态.
 */
#define LOCKED   0
#define UNLOCKED 1

#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
int32_t env_create_sync_lock(void **lock, int32_t state, void *context);
#else
int32_t env_create_sync_lock(void **lock, int32_t state);
#endif

/**
 * @brief  删除同步锁.
 * @param  lock 指向要删除的同步锁的指针.
 */
void env_delete_sync_lock(void *lock);

/**
 * @brief  尝试获取同步锁.
 * @param  lock 指向要获取的同步锁的指针.
 */
void env_acquire_sync_lock(void *lock);

/**
 * @brief  释放同步锁.
 * @param  lock 指向要是否的同步锁的指针.
 */
void env_release_sync_lock(void *lock);

/**
 * @brief  指定当前线程挂起时间, 即线程延时.
 * @param  num_msec 延时时间, 单位: 毫秒.
 */
void env_sleep_msec(uint32_t num_msec);

/**
 * @brief  指定中断注册中断处理程序.
 * @param  env 指向环境上下文数据的指针.
 * @param  vector_id 虚拟中断的中断号.
 * @param  data 中断处理器数据(virtqueue).
 */
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
void env_register_isr(void *env, uint32_t vector_id, void *data);
#else
void env_register_isr(uint32_t vector_id, void *data);
#endif

/**
 * @brief  指定中断卸载中断处理程序.
 * @param  env 指向环境上下文数据的指针.
 * @param  vector_id 虚拟中断的中断号.
 */
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
void env_unregister_isr(void *env, uint32_t vector_id);
#else
void env_unregister_isr(uint32_t vector_id);
#endif

/**
 * @brief  启用指定中断.
 * @param  env 指向环境上下文数据的指针.
 * @param  vector_id 虚拟中断的中断号.
 */
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
void env_enable_interrupt(void *env, uint32_t vector_id);
#else
void env_enable_interrupt(uint32_t vector_id);
#endif

/**
 * @brief  禁用指定中断.
 * @param  env 指向环境上下文数据的指针.
 * @param  vector_id 虚拟中断的中断号.
 */
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
void env_disable_interrupt(void *env, uint32_t vector_id);
#else
void env_disable_interrupt(uint32_t vector_id);
#endif

/**
 * @brief  为给定的内存区域启用内存映射.
 * @param  pa 内存的物理地址.
 * @param  va 内存的裸机地址.
 * @param  size 内存大小.
 * @param  flags 缓存/非缓存和访问类型的标志.
 *
 * 目前只使用flag参数的第一个字节, 位映射定义如下:
 *
 * 缓存位
 * 0x0000_0001 = 无缓存
 * 0x0000_0010 = 写回
 * 0x0000_0100 = 写通
 * 0x0000_x000 = 未使用
 *
 * 存储类型
 * 0x0001_xxxx = 内存映射
 * 0x0010_xxxx = IO映射
 * 0x0100_xxxx = 共享
 * 0x1000_xxxx = TLB
 */

/* 用于共享内存使用的缓存方案的宏 */
#define UNCACHED     (1 << 0)
#define WB_CACHE     (1 << 1)
#define WT_CACHE     (1 << 2)

/* 存储类型 */
#define MEM_MAPPED   (1 << 4)
#define IO_MAPPED    (1 << 5)
#define SHARED_MEM   (1 << 6)
#define TLB_MEM      (1 << 7)

void env_map_memory(uint32_t pa, uint32_t va, uint32_t size, uint32_t flags);

/**
 * @brief  获取一个64位的时间戳.
 * @return 返回64位的时间戳.
 */
uint64_t env_get_timestamp(void);

/** @brief 禁用系统缓存. */
void env_disable_cache(void);

typedef void LOCK;

/**
 * @brief  创建消息队列.
 * @param  queue 指向创建的队列的指针.
 * @param  length 队列中元素的最大个数.
 * @param  item_size 队列中元素的大小, 单位: 字节.
 * @param  queue_static_storage 指向队列静态存储缓冲区的指针.
 * @param  queue_static_context 指向队列静态上下文的指针.
 * @return 返回函数的执行状态.
 */
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
int32_t env_create_queue(void **queue, int32_t length, int32_t element_size,
   uint8_t *queue_static_storage, rpmsg_static_queue_ctxt *queue_static_context);
#else
int32_t env_create_queue(void **queue, int32_t length, int32_t element_size);
#endif

/**
 * @brief  删除消息队列.
 * @param  queue 指向要删除的队列的指针.
 */

void env_delete_queue(void *queue);

/**
 * @brief  向队列中放入一个元素.
 * @param  queue 指向放入元素的队列的指针.
 * @param  msg 指向要放入队列的消息的指针.
 * @param  timeout_ms 超时时间, 毫秒.
 * @return 返回函数的执行状态.
 */
int32_t env_put_queue(void *queue, void *msg, uint32_t timeout_ms);

/**
 * @brief  从队列中获取一个元素.
 * @param  queue 指向获取元素的队列的指针.
 * @param  msg 指向存储消息的内存的指针.
 * @param  timeout_ms 超时时间, 毫秒.
 * @return 返回函数的执行状态.
 */
int32_t env_get_queue(void *queue, void *msg, uint32_t timeout_ms);

/**
 * @brief  获取队列大小.
 * @param  queue 指向队列的指针.
 * @return 队列中排队的元素的个数.
 */
int32_t env_get_current_queue_size(void *queue);

/**
 * @brief  调用RPMSG/IRQ回调.
 * @param  env 指向环境上下文数据的指针.
 * @param  vector RPMSG IRQ中断ID.
 */
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
void env_isr(void *env, uint32_t vector);
#else
void env_isr(uint32_t vector);
#endif

#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
/**
 * @brief  从环境上下文中获取平台层上下文.
 * @param  env 指向环境上下文数据的指针.
 * @return 返回平台层上下文数据的指针.
 */
void *env_get_platform_context(void *env_context);

/**
 * @brief  初始化指定虚拟队列中断的ISR数据.
 * @param  env 指向环境上下文数据的指针.
 * @param  vq_id 虚拟队列ID.
 * @param  isr_data 指向初始ISR数据的指针.
 * @return 函数执行状态, 成功时返回0.
 */
int32_t env_init_interrupt(void *env, int32_t vq_id, void *isr_data);

/**
 * @brief  反初始化指定virtqueue中断的ISR数据.
 * @param  env 指向环境上下文数据的指针.
 * @param  vq_id 虚拟队列ID.
 * @return 函数执行状态, 成功时返回0.
 */
int32_t env_deinit_interrupt(void *env, int32_t vq_id);
#endif

/**
 * @brief  rpmsg_lite_wait_for_link_up函数的具体实现, 使用RTOS同步.
 *         避免忙循环的原语. 链接启动后返回.
 * @param  link_state 指向RPMsg-Lite实例结构体的link_state参数的指针.
 * @param  link_id RPMsg-Lite实例的链接ID, 请参见rpmsg_platform.h
 * @param  timeout_ms 超时时间, 单位: 毫秒.
 * @return 连接时返回RL_TRUE, 超时时返回RL_FALSE.
 */
uint32_t env_wait_for_link_up(volatile uint32_t *link_state,
                              uint32_t link_id, uint32_t timeout_ms);

/**
 * @brief  从rpmsg_lite_tx_callback()调用, 允许解阻塞env_wait_for_link_up().
 * @param  link_id RPMsg-Lite实例的链接ID, 请参见rpmsg_platform.h
 */
void env_tx_callback(uint32_t link_id);

#endif /* RPMSG_ENV_H_ */
